#include "grass.h"
#include <string>
#include <cmath>
Grass::Grass()
{
	m_grassShader = new glutil::ShaderProgram;
	m_grassShader->attachShaderFromFile(GL_VERTEX_SHADER,"data/grass.vert");
	m_grassShader->attachShaderFromFile(GL_FRAGMENT_SHADER,"data/grass.frag");
	m_grassShader->link();
	m_grassShader->setUniform1i("grassTexture",0);
	m_grassShader->setUniform1f("tuftWidth",0.5);
	m_grassShader->setUniform1f("tuftHeight",0.05);
    }

void Grass::generateVBO(GrassTypeInfo& grass, const std::vector<geom::Point3D> &points )	
{
	int numPoints = points.size();
	float * tva = new float[numPoints * 4*3];     // vertices array
	float * tca = new float[numPoints * 4*3];     // texture coordinates array

	for(int i=0;i<numPoints;++i)
	{
		const geom::Point3D &p = points[i];
		float randomSide = sin(7.5*i+5.211*p.z+1.2*p.x*i) + cos(30+10.3*i+2.7*p.z);

		tva[i*12 +0] = p.x;  tva[i*12 + 1] = p.y;  tva[i*12 + 2] = p.z;
		
		tva[i*12 +3] = p.x;  tva[i*12 + 4] = p.y;  tva[i*12 + 5] = p.z;
		tva[i*12 +6] = p.x;  tva[i*12 + 7] = p.y;  tva[i*12 + 8] = p.z;
		tva[i*12 +9] = p.x;  tva[i*12 +10] = p.y;  tva[i*12 +11] = p.z;

		tca[i*12 +0] = 0;	tca[i*12 +1] = 0;	tca[i*12 +2] = randomSide;
		tca[i*12 +3] = 1;	tca[i*12 +4] = 0;	tca[i*12 +5] = randomSide;
		tca[i*12 +6] = 1;	tca[i*12 +7] = 1;	tca[i*12 +8] = randomSide;
		tca[i*12 +9] = 0;	tca[i*12 +10] = 1;	tca[i*12 +11] = randomSide;
	}

	if(grass.vbufferID == 0)
	{
		glGenBuffers(1,&grass.vbufferID);
		glGenBuffers(1,&grass.tcbufferID);
	}


	glBindBuffer(GL_ARRAY_BUFFER,grass.vbufferID);
	glBufferData(GL_ARRAY_BUFFER,3*4*sizeof(float)*numPoints,tva,GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER,grass.tcbufferID);
	glBufferData(GL_ARRAY_BUFFER,3*4*sizeof(float)*numPoints,tca,GL_STATIC_DRAW);

	glBindBuffer(GL_ARRAY_BUFFER,0);

	delete [] tva;
	delete [] tca;
}

void Grass::draw(int windowWidth)
{
	glEnable(GL_TEXTURE_2D);
	glActiveTexture(GL_TEXTURE0);
	m_grassShader->setUniform1f("windowWidth",windowWidth);
	m_grassShader->bind();
	for(unsigned int i =0;i<m_grassTypes.size();++i)
	{
		const GrassTypeInfo &g = m_grassTypes[i];
		glBindTexture(GL_TEXTURE_2D,g.textureID);
		m_grassShader->setUniform1f("tuftHeight",g.textureHeight*g.scale);
		m_grassShader->setUniform1f("tuftWidth",g.textureWidth * g.scale);
		glEnableClientState(GL_VERTEX_ARRAY);
		glBindBuffer(GL_ARRAY_BUFFER,g.vbufferID);
		glVertexPointer(3,GL_FLOAT,0,0);
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glBindBuffer(GL_ARRAY_BUFFER,g.tcbufferID);
		glTexCoordPointer(3,GL_FLOAT,0,0);

		glDrawArrays(GL_QUADS,0,g.numElems*4);
	}
	glDisableClientState(GL_VERTEX_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	
	m_grassShader->unbind();
	glBindTexture(GL_TEXTURE_2D,0);
}

void Grass::addGrassType(GLuint textureID, int textureWidth, int textureHeight, float density, float scale)
{
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D,textureID);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);

	GrassTypeInfo grass;
	grass.textureWidth = textureWidth;
	grass.textureHeight = textureHeight;
	grass.density = density;
	grass.textureID = textureID;
	grass.scale = scale;

	std::vector<geom::Point3D> points;
	grass.numElems = int(density * 200000);

	for(int i=0;i<grass.numElems;++i)
	{
		float radius = rand()/(float)RAND_MAX*300;
		float angle = rand()/(float)RAND_MAX*2*M_PI;
		float xMove = sqrt(radius) * cos(angle);
		float zMove = sqrt(radius) * sin(angle);
		points.push_back(geom::Point3D(xMove,0,zMove));
	}
	generateVBO(grass,points);
	m_grassTypes.push_back(grass);
}

